home *** CD-ROM | disk | FTP | other *** search
/ Amiga Games: 500 MB Amiga Software / 500 MB Amiga Software - Euber 130 - Amiga Games Disc & Mag.iso / userbox / publicdomain / filer / rexx / picasso.filer < prev    next >
Text File  |  1995-01-12  |  23KB  |  591 lines

  1. /*
  2.     $VER: Picasso.filer 1.7 (16.12.94)
  3.  
  4.     Author:
  5.         Michael Böhnisch (billy@uni-paderborn.de)   (mb)
  6.         Matthias Scheler (tron@lyssa.pb.owl.de)     (ms)
  7.  
  8.     Function:
  9.         ViewGIF,  the  GIF  viewer that accompanies the Picasso II graphics
  10.         board,  often  selects  wrong resolutions when displaying oversized
  11.         pictures.   E.g.   I´ve  got  a  picture,  600×800 in size, ViewGIF
  12.         displays  on  a  1024×768  screen,  cropping off the lower 34 rows.
  13.         Picasso.filer  scans  the  GIF file for the picture size and forces
  14.         ViewGIF into a better resolution.
  15.  
  16.         ViewJPEG  uses  640×480×24  by default, regardless whether it crops
  17.         the  image  or not.  I prefer seeing the whole image when possible,
  18.         so Picasso.filer allows 16 or 8 bits per pixel resolutions.  Bigger
  19.         pictures  may  take a while to display, especially on unaccelerated
  20.         Amigas.  Stay patient.
  21.  
  22.         ViewIFF   does   not  show  Multi  Palette  pictures  (PCHG  chunk)
  23.         correctly.  Picasso.filer provides a fallback to an external viewer
  24.         when such pictures are selected.
  25.         Pixels  on  the  Picasso  II board usually are square shaped, or in
  26.         other  words  have  an  X/Y  aspect  ratio  of  1.  This results in
  27.         distorted picture displays for special view modes like  "NTSC:LoRes
  28.         Lace".
  29.         Picasso.filer handles this by supplying one of the keywords DOUBLEX
  30.         or  DOUBLEY  to  ViewIFF  as  appropriate.  For extreme distortions
  31.         (e.g.   pictures for PAL:SuperHighres non-interlaced) a fallback to
  32.         an  external  external  viewer  on  conservative  Amiga  screens is
  33.         choosen.
  34.  
  35.     Requires:
  36.         Picasso II graphics board
  37.         ViewGIF, ViewJPEG and ViewIFF supplied with Picasso II
  38.         VT  2.0  by Thomas Krehbiel or any other standard IFF viewer.  Must
  39.         support  PCHG  Multi  Palette  pictures  if  you  want to view this
  40.         picture type.
  41.  
  42.     Call:
  43.         Picasso TYPE FILE
  44.  
  45.         Where  TYPE is one of GIF, IFF or JPG.  Picasso.filer relies on the
  46.         correctness of this info and does no further file type checking.
  47.  
  48.     Example for "Filer.RC":
  49.         REXXCLASS "#?","GIF8","Picasso GIF %s"
  50.         REXXCLASS "#?","??????JFIF","Picasso JPG %s"
  51.         REXXCLASS "#?","FORM????ILBM","Picasso IFF %s"
  52.  
  53.     ToDo:
  54.         IFF pictures with aspect ratios outside the range from 0.35 to 2.83
  55.         are displayed on standard Amiga screens.  Maybe some tool should be
  56.         used  to do a scale operation on the picture first and then forward
  57.         it to the Picasso viewer.
  58.  
  59.     History:
  60.         06.02.94    1.0 Initial Release                             (mb)
  61.         07.02.94    1.1 IFF & JPEG added                            (mb)
  62.         08.02.94    1.2 fallback for HAM/EHB pictures removed       (ms)
  63.         09.02.94    1.3 removed VT dependency for GIF
  64.                         removed VT dependency for IFF, any viewer
  65.                         wil do now
  66.                         added IFF PCHG fallback
  67.                         added fallback for non-square aspect ratios (mb)
  68.         10.02.94    1.4 used ViewIFF keywords DOUBLEX and DOUBLEY
  69.                         for a wider range of pictures displayed on
  70.                         the Picasso II                              (mb)
  71.         10.03.94    1.5 removed VT dependency for JPEG
  72.                         no need for rexxsupport.library any longer
  73.                         added user confirmation for oversized JPEGs (mb)
  74.         25.11.94    1.6 Bugfix: GIF files with extension block
  75.                         present were not displayed                  (mb)
  76.         16.12.94    1.7 Added some support for nested IFF FORMS     (mb)
  77. */
  78.  
  79. /* -------------------------------------------------------------------- */
  80. /* External commands. Adjust these to your individual settings.         */
  81. /* -------------------------------------------------------------------- */
  82.  
  83. vtcommand = "VT"
  84. vgcommand = "ViewGIF"
  85. vjcommand = "ViewJPEG"
  86. vicommand = "ViewIFF"
  87.  
  88. /* -------------------------------------------------------------------- */
  89.  
  90. OPTIONS RESULTS                     /* we need response from filer      */
  91.  
  92. PARSE ARG TYPE PICFILE              /* get arguments                    */
  93. TYPE    = STRIP( TYPE )
  94. PICFILE = STRIP( PICFILE )
  95.  
  96. /* -------------------------------------------------------------------- */
  97. /* Default to Filer's AReXX port and prevent Filer from quitting        */
  98. /* -------------------------------------------------------------------- */
  99.  
  100. ADDRESS 'FilerRexx'
  101.  
  102. LOCKFILER
  103. Key = RESULT
  104.  
  105. /* -------------------------------------------------------------------- */
  106. /* Get source dircetory name, append "/" if it is not a device name.    */
  107. /* Tag name of file to view.                                            */
  108. /* -------------------------------------------------------------------- */
  109.  
  110. GETSOURCEPATH
  111. SrcPath = RESULT
  112.  
  113. IF RIGHT(SrcPath, 1) = ':' THEN
  114.     FileName = SrcPath || STRIP( PICFILE, B, X2C(22) )
  115. ELSE
  116.     FileName = SrcPath || '/' || STRIP( PICFILE, B, X2C(22) )
  117.  
  118. SELECT
  119.  
  120.     /* ---------------------------------------------------------------- */
  121.     /* Show GIF picture                                                 */
  122.     /* ---------------------------------------------------------------- */
  123.  
  124.     WHEN TYPE = 'GIF' THEN DO
  125.  
  126.         /* ------------------------------------------------------------ */
  127.         /* determine ViewGIF RESOLUTION parameter and call viewer       */
  128.         /* ------------------------------------------------------------ */
  129.  
  130.         CALL GIFSize
  131.         PARSE VAR RESULT xsize ysize depth
  132.         xsize = STRIP( xsize )
  133.         ysize = STRIP( ysize )
  134.         depth = STRIP( depth )
  135.  
  136.         res = 1600
  137.         IF ( xsize <= 1280 ) & ( ysize <= 1024 ) THEN res = 1280
  138.         IF ( xsize <= 1152 ) & ( ysize <=  900 ) THEN res = 1152
  139.         IF ( xsize <= 1120 ) & ( ysize <=  832 ) THEN res = 1120
  140.         IF ( xsize <= 1024 ) & ( ysize <=  768 ) THEN res = 1024
  141.         IF ( xsize <=  800 ) & ( ysize <=  600 ) THEN res =  800
  142.         IF ( xsize <=  640 ) & ( ysize <=  480 ) THEN res =  640
  143.         IF ( xsize <=  320 ) & ( ysize <=  240 ) THEN res =  320
  144.  
  145.         HISTORY 'Picasso: GIF "' || FileName || '"' xsize || '×' || ysize || '×' || depth
  146.  
  147.         SHELL COMMAND vgcommand RESOLUTION res CENTER FileName '>NIL:'
  148.  
  149.     END
  150.  
  151.     /* ---------------------------------------------------------------- */
  152.     /* Show JPG picture                                                 */
  153.     /* ---------------------------------------------------------------- */
  154.  
  155.     WHEN TYPE = 'JPG' THEN DO
  156.  
  157.         /* ------------------------------------------------------------ */
  158.         /* Determine JPEG picture size                                  */
  159.         /* ------------------------------------------------------------ */
  160.  
  161.         CALL JPGSize
  162.         PARSE VAR RESULT xsize ysize depth
  163.         xsize = STRIP( xsize )
  164.         ysize = STRIP( ysize )
  165.         depth = STRIP( depth )
  166.  
  167.         /* ------------------------------------------------------------ */
  168.         /* choose maximum number of colors available without cropping   */
  169.         /* and call ViewJPG                                             */
  170.         /* ------------------------------------------------------------ */
  171.  
  172.         dep = '8BIT'
  173.         IF ( xsize <= 1152 ) & ( ysize <=  900 ) THEN dep = '16BIT'
  174.         IF ( xsize <=  800 ) & ( ysize <=  600 ) THEN dep = '24BIT'
  175.  
  176.         banner = xsize || '×' || ysize || '×' || depth
  177.  
  178.         HISTORY 'Picasso: JPG "' || FileName || '"' banner '(' || dep || ')'
  179.  
  180.         /* ------------------------------------------------------------ */
  181.         /* Ask for confirmation if picture is "on the big side"         */
  182.         /* ------------------------------------------------------------ */
  183.  
  184.         display = 1
  185.         IF xsize * ysize > 1000000 THEN DO
  186.             txt =        "This operation may take a long time.|"
  187.             txt = txt || "      Shall I continue anyway?"
  188.  
  189.             QUESTBOX txt
  190.             display = RESULT
  191.         END
  192.  
  193.         IF display = 1 THEN SHELL COMMAND vjcommand dep FileName '>NIL:'
  194.  
  195.     END
  196.  
  197.     /* ---------------------------------------------------------------- */
  198.     /* Show IFF ILBM picture                                            */
  199.     /* ---------------------------------------------------------------- */
  200.  
  201.     WHEN TYPE = IFF THEN DO
  202.  
  203.         /* ------------------------------------------------------------ */
  204.         /* determine size and depth of the picture                      */
  205.         /* ------------------------------------------------------------ */
  206.  
  207.         CALL IFFSize
  208.         PARSE VAR RESULT xsize ysize depth ratio
  209.         xsize = STRIP( xsize )
  210.         ysize = STRIP( ysize )
  211.         depth = STRIP( depth )
  212.         ratio = STRIP( ratio )
  213.  
  214.         banner = xsize || '×' || ysize || '×' || depth
  215.  
  216.         /* ------------------------------------------------------------ */
  217.         /* Does the IFF file contain a PCHG chunk? These pictures may   */
  218.         /* have a dedicated palette for each scanline and currently are */
  219.         /* not displayed correctly by ViewIFF.                          */
  220.         /* ------------------------------------------------------------ */
  221.  
  222.         CALL PCHGTest
  223.         test = RESULT
  224.  
  225.         SELECT
  226.  
  227.             WHEN test = 'ERRR' THEN DO
  228.  
  229.                 /* ---------------------------------------------------- */
  230.                 /* An error occured, inform user and exit               */
  231.                 /* ---------------------------------------------------- */
  232.  
  233.                 HISTORY 'Picasso: error processing' FileName
  234.  
  235.             END
  236.  
  237.             WHEN test = 'PCHG' THEN DO
  238.  
  239.                 /* ---------------------------------------------------- */
  240.                 /* Display Multi-Palette picture                        */
  241.                 /* ---------------------------------------------------- */
  242.  
  243.                 HISTORY 'Picasso: IFF "' || FileName || '"' banner '(PCHG)'
  244.                 SHELL COMMAND vtcommand FileName '>NIL:'
  245.  
  246.             END
  247.  
  248.             /* -------------------------------------------------------- */
  249.             /* do some correction of aspect ratios in number range      */
  250.             /* 0.35 = sqrt(0.5) ... 2.83 = 2 * sqrt(2)                  */
  251.             /* by ViewIFF options DOUBLEX and DOUBLEY                   */
  252.             /* -------------------------------------------------------- */
  253.  
  254.             WHEN ( ratio < 0.71 ) & ( ratio >= 0.35 ) THEN DO
  255.  
  256.                 /* ---------------------------------------------------- */
  257.                 /* Pixels are about half as wide than tall              */
  258.                 /* ---------------------------------------------------- */
  259.  
  260.                 HISTORY 'Picasso: IFF "' || FileName || '"' banner '(X:Y =' ratio || ')'
  261.                 SHELL COMMAND vicommand CENTER MODE DOUBLEY FileName '>NIL:'
  262.                 
  263.             END
  264.  
  265.             WHEN ( ratio < 1.41 ) & ( ratio >= 0.71 ) THEN DO
  266.  
  267.                 /* ---------------------------------------------------- */
  268.                 /* Take this for square, some distortion tolerated      */
  269.                 /* ---------------------------------------------------- */
  270.  
  271.                 HISTORY 'Picasso: IFF "' || FileName || '"' banner '(X:Y =' ratio || ')'
  272.                 SHELL COMMAND vicommand CENTER FileName '>NIL:'
  273.                 
  274.             END
  275.  
  276.             WHEN ( ratio < 2.83 ) & ( ratio >= 1.41 ) THEN DO
  277.  
  278.                 /* ---------------------------------------------------- */
  279.                 /* Pixels are about twice as wide than tall             */
  280.                 /* ---------------------------------------------------- */
  281.  
  282.                 HISTORY 'Picasso: IFF "' || FileName || '"' banner '(X:Y =' ratio || ')'
  283.                 SHELL COMMAND vicommand CENTER MODE DOUBLEX FileName '>NIL:'
  284.                 
  285.             END
  286.  
  287.             OTHERWISE DO
  288.  
  289.                 /* ---------------------------------------------------- */
  290.                 /* Fall back to externalviewer if outside aspect bounds */
  291.                 /* This should happen very rarely, e.g. for pictures in */
  292.                 /* Superhires without interlace (aspect ratio ~ 4) or   */
  293.                 /* Multiscan productivity with interlace (aspect ratio  */
  294.                 /* ~ 0.25)                                              */
  295.                 /* ---------------------------------------------------- */
  296.  
  297.                 HISTORY  'Picasso: IFF "' || FileName || '"' banner '(X:Y =' ratio || 'FB)'
  298.                 SHELL COMMAND vtcommand FileName '>NIL:'
  299.  
  300.             END
  301.  
  302.         END
  303.  
  304.     END
  305.  
  306.     /* ---------------------------------------------------------------- */
  307.     /* unknown type                                                     */
  308.     /* ---------------------------------------------------------------- */
  309.  
  310.     OTHERWISE DO
  311.  
  312.         /* ------------------------------------------------------------ */
  313.         /* Wrong type parameter, inform user                            */
  314.         /* ------------------------------------------------------------ */
  315.  
  316.         HISTORY 'Picasso: Type' TYPE 'not supported'
  317.  
  318.     END
  319.             
  320. END
  321.  
  322. /* -------------------------------------------------------------------- */
  323. /* re-allow quitting Filer                                              */
  324. /* -------------------------------------------------------------------- */
  325.  
  326. UNLOCKFILER Key
  327.  
  328. EXIT
  329.  
  330. /************************************************************************/
  331. /* JPGSize : subroutine parses a JFIF file and returns the picture's    */
  332. /*           dimensions                                                 */
  333. /************************************************************************/
  334.  
  335. JPGSize: PROCEDURE EXPOSE FileName
  336.  
  337.     M_SOF0 = X2C( C0 )      /* SOF code for arithmetic encoding         */
  338.     M_SOF1 = X2C( C1 )      /* SOF code for baseline implementation     */
  339.     M_SOF9 = X2C( C9 )      /* SOF code for non-baseline Huffmann file  */
  340.  
  341.     IF OPEN( jpg, FileName, 'READ' ) THEN DO
  342.  
  343.         /* ------------------------------------------------------------ */
  344.         /* skip over SOI marker                                         */
  345.         /* ------------------------------------------------------------ */
  346.  
  347.         SEEK( jpg, 2, 'BEGIN' )     /* point to JFIF APP0 block         */
  348.  
  349.         /* ------------------------------------------------------------ */
  350.         /* Loop through data blocks until EOF or a SOF block is found   */
  351.         /* ------------------------------------------------------------ */
  352.  
  353.         DO UNTIL EOF( jpg )
  354.  
  355.             IF READCH( jpg ) ~= X2C( FF ) THEN RETURN
  356.  
  357.             /* -------------------------------------------------------- */
  358.             /* Get block type marker                                    */
  359.             /* -------------------------------------------------------- */
  360.  
  361.             type = READCH( jpg )
  362.  
  363.             /* -------------------------------------------------------- */
  364.             /* Test for SOF block                                       */
  365.             /* -------------------------------------------------------- */
  366.  
  367.             IF type = M_SOF0 | type = M_SOF1 | type = M_SOF9 THEN DO
  368.  
  369.                 /* ---------------------------------------------------- */
  370.                 /* Skip to size information words                       */
  371.                 /* ---------------------------------------------------- */
  372.  
  373.                 SEEK( jpg, 3, 'CURRENT' )
  374.  
  375.                 /* ---------------------------------------------------- */
  376.                 /* read size information and return to calling proc     */
  377.                 /* ---------------------------------------------------- */
  378.  
  379.                 hi = C2D( READCH( jpg ) )
  380.                 lo = C2D( READCH( jpg ) )
  381.                 h  = lo + 256 * hi
  382.  
  383.                 hi = C2D( READCH( jpg ) )
  384.                 lo = C2D( READCH( jpg ) )
  385.                 w  = lo + 256 * hi
  386.  
  387.                 CLOSE( jpg )
  388.  
  389.                 RETURN w h 24
  390.             END
  391.  
  392.             /* -------------------------------------------------------- */
  393.             /* No SOF, skip to next marker                              */
  394.             /* -------------------------------------------------------- */
  395.  
  396.             hi = C2D( READCH( jpg ) )
  397.             lo = C2D( READCH( jpg ) )
  398.  
  399.             SEEK( jpg, lo + 256 * hi - 2, 'CURRENT' )
  400.         END
  401.  
  402.         CLOSE( jpg )
  403.  
  404.     END
  405.  
  406.     RETURN
  407.  
  408. /************************************************************************/
  409. /* GIFSize : subroutine parses a GIF file and returns the picture's     */
  410. /*           dimensions                                                 */
  411. /************************************************************************/
  412.  
  413. GIFSize: PROCEDURE EXPOSE FileName
  414.  
  415.     IF OPEN( gif, FileName, 'READ' ) THEN DO
  416.  
  417.         /* ------------------------------------------------------------ */
  418.         /* extract colour depth information                             */
  419.         /* ------------------------------------------------------------ */
  420.  
  421.         SEEK( gif, 10, 'BEGIN' )    /* point to resolution flag reg.    */
  422.  
  423.         rf = C2D( READCH( gif ) )   /* resolution flag register         */
  424.         r  = ( rf // 8 ) + 1        /* extract bits/pixel               */
  425.  
  426.         SEEK( gif, 13, 'BEGIN' )    /* point behind screen descriptor   */
  427.  
  428.         /* ------------------------------------------------------------ */
  429.         /* skip global colour map if present                            */
  430.         /* ------------------------------------------------------------ */
  431.  
  432.         IF rf >= 128 THEN SEEK( gif, 3 * 2**r, 'CURRENT' )
  433.  
  434.         /* ------------------------------------------------------------ */
  435.         /* skip extension block if present                              */
  436.         /* ------------------------------------------------------------ */
  437.  
  438.         IF READCH( gif ) = '!' THEN DO          /* read header          */
  439.  
  440.             SEEK( gif, 1, 'CURRENT' )           /* skip function code   */
  441.             DO UNTIL len = 0                    /* up to last block     */
  442.                 len = C2D( READCH( gif ) )      /* get data block size  */
  443.                 SEEK( gif, len, 'CURRENT' )     /* skip data block      */
  444.             END
  445.             SEEK( gif, 1, 'CURRENT' )           /* skip next header     */
  446.  
  447.         END
  448.             
  449.         /* ------------------------------------------------------------ */
  450.         /* The image descriptor block is reached, at last. Now let's    */
  451.         /* look for the actual image size...                            */
  452.         /* ------------------------------------------------------------ */
  453.  
  454.         SEEK( gif, 4, 'CURRENT' )               /* skip topleft coords  */
  455.  
  456.         /* ------------------------------------------------------------ */
  457.         /* all numbers are stored in INTEL format, lo-byte first        */
  458.         /* ------------------------------------------------------------ */
  459.  
  460.         lo = C2D( READCH( gif ) )               /* get width            */
  461.         hi = C2D( READCH( gif ) )
  462.         w  = lo + 256 * hi
  463.  
  464.         lo = C2D( READCH( gif ) )               /* get height           */
  465.         hi = C2D( READCH( gif ) )
  466.         h  = lo + 256 * hi
  467.  
  468.         CLOSE( gif )
  469.  
  470.         RETURN w h r
  471.  
  472.     END
  473.  
  474.     RETURN
  475.  
  476. /************************************************************************/
  477. /* IFFSize : subroutine parses an IFF ILBM file and returns the picture */
  478. /*           size and pixel aspect ratio                                */
  479. /************************************************************************/
  480.  
  481. IFFSize: PROCEDURE EXPOSE FileName
  482.  
  483.     IF OPEN( iff, FileName, 'READ' ) THEN DO
  484.  
  485.         /* ------------------------------------------------------------ */
  486.         /* File starts with FORM????ILBM.                               */
  487.         /* ------------------------------------------------------------ */
  488.  
  489.         len = 12                    /* offset for first chunk in file   */
  490.  
  491.         DO UNTIL type = 'BMHD'
  492.  
  493.             /* -------------------------------------------------------- */
  494.             /* seek to next chunk                                       */
  495.             /* -------------------------------------------------------- */
  496.  
  497.             SEEK( iff, len, 'CURRENT' )
  498.  
  499.             /* -------------------------------------------------------- */
  500.             /* parse out chunk type and length                          */
  501.             /* -------------------------------------------------------- */
  502.  
  503.             type = READCH( iff, 4 )
  504.  
  505.             IF type = 'FORM' THEN
  506.                 len = 8;
  507.             ELSE DO
  508.                 len  =             C2D( READCH( iff ) )
  509.                 len  = len * 256 + C2D( READCH( iff ) )
  510.                 len  = len * 256 + C2D( READCH( iff ) )
  511.                 len  = len * 256 + C2D( READCH( iff ) )
  512.             END
  513.  
  514.             IF len // 2 = 1 THEN len = len + 1  /* add 1 for odd length */
  515.  
  516.         END
  517.  
  518.         /* ------------------------------------------------------------ */
  519.         /* We're now positioned on a BMHD chunk.                        */
  520.         /* ------------------------------------------------------------ */
  521.  
  522.         hi = C2D( READCH( iff ) )   /* read image width                 */
  523.         lo = C2D( READCH( iff ) )
  524.         w  = lo + 256 * hi
  525.  
  526.         hi = C2D( READCH( iff ) )   /* read image height                */
  527.         lo = C2D( READCH( iff ) )
  528.         h  = lo + 256 * hi
  529.  
  530.         SEEK( iff, 4, 'CURRENT' )   /* seek to nPlanes entry            */
  531.  
  532.         d  = C2D( READCH( iff ) )   /* number of bitplanes (depth)      */
  533.  
  534.         SEEK( iff, 5, 'CURRENT' )   /* seek to aspect ratio entries     */
  535.  
  536.         xa = C2D( READCH( iff ) )   /* xAspect                          */
  537.         ya = C2D( READCH( iff ) )   /* yAspect                          */
  538.  
  539.         NUMERIC DIGITS 3            /* sometimes less is more...        */
  540.         a  = xa / ya                /* Aspect ratio                     */
  541.         NUMERIC DIGITS
  542.  
  543.         CLOSE( iff )                /* clean up                         */
  544.  
  545.         RETURN w h d a
  546.     END
  547.  
  548.     RETURN
  549.  
  550. /************************************************************************/
  551. /* PCHGTest : Returns true if IFFFile contains a PCHG chunk and thus,   */
  552. /*            is not correctly displayed by ViewIFF.                    */
  553. /************************************************************************/
  554.  
  555. PCHGTest: PROCEDURE EXPOSE FileName
  556.  
  557.     IF OPEN( iff, FileName, "READ" ) THEN DO
  558.  
  559.         len = 12
  560.  
  561.         DO UNTIL ( Type = 'PCHG' ) | EOF( iff )
  562.  
  563.             SEEK( iff, len, 'CURRENT' )
  564.  
  565.             type = READCH( iff, 4 )
  566.  
  567.             IF type = 'FORM' THEN
  568.                 len = 8;
  569.             ELSE DO
  570.                 b1   = C2D( READCH( iff ) ) * 2**24
  571.                 b2   = C2D( READCH( iff ) ) * 2**16
  572.                 b3   = C2D( READCH( iff ) ) * 2**8
  573.                 b4   = C2D( READCH( iff ) )
  574.                 len  = b1 + b2 + b3 + b4
  575.             END
  576.  
  577.             IF len // 2 = 1 THEN len = len + 1  /* add 1 for odd length */
  578.  
  579.         END
  580.  
  581.         CLOSE( iff )
  582.  
  583.         IF Type = 'PCHG' THEN
  584.             RETURN 'PCHG'
  585.         ELSE
  586.             RETURN 'NORM'
  587.  
  588.     END
  589.  
  590.     RETURN 'ERROR'
  591.